package com;

import java.net.Socket;
import java.sql.Connection;

// 不允许类被继承
public final class Singleton5 {
    // 实例变量
    private String name = "1234";

    // 如果实例变量是某个对象的时候,会有可能报空指针错误
    // 这里它需要实例3个对象 conn,socket,Singleton5
    // 实际上在jvm运行的时候有个指令重排序, 这三个的先后顺序 不能保证, 如果Singleton5 在先实例化了,conn和 socket 没有实例化
    // 那么这个时候另外一个线程进来,就会直接拿到这个对象返回, 当它马上使用 conn 和 socket 变量的时候就是空的
    private Connection conn;
    private Socket socket;

    // 定义实例变量的时候直接初始化
    // volatile 可以保证原子性, (网上也有说法是说可以禁用cpu的缓存, 具体的我就不清楚了)
    // 这个关键字, 可以防止重排序的发生,这样就完美了
    private volatile static Singleton5 instance = null;

    // 私有化构造函数, 不允许外部new
    private Singleton5() {
    }

    /**
     * 这里和第4中的写法是一样的 不一样的在定义静态变量上加了一个 volatile 关键字
     * @return
     */
    public static Singleton5 getInstance() {
        // 当 instance 为空时, 进入同步代码块,同时也避免了每次都要进入同步代码块, 可以调效率
        if (instance == null) {
            // 只有一个线程可以拿到Singleton4 的监视器
            synchronized (Singleton5.class){
                // 第二遍检查, 判断为null 时创建对象,
                if (instance == null) {
                    instance = new Singleton5();
                }

            }
        }
        return instance;
    }
}
